/***************************************************************************
 *   Copyright (C) 2008 by Goliash   *
 *   goliash@goliash.net   *
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 *   This program is distributed in the hope that it will be useful,       *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 *   GNU General Public License for more details.                          *
 *                                                                         *
 *   You should have received a copy of the GNU General Public License     *
 *   along with this program; if not, write to the                         *
 *   Free Software Foundation, Inc.,                                       *
 *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
 ***************************************************************************/

#include "medium.h"

Medium::Medium()
{
	Preferences * prefs = Preferences::instance();
	device = prefs->device;
	
	// finding out the mount point of the device
	mount_point = getMountPointOfDevice(device);
	filesystem = "iso9660";
	/*QString label = "burn motherfucker";
	state = scanISO9660();
	if(state != 0) label = "xx";
	emit stateChanged(label);*/
}

Medium::~Medium()
{
}

int Medium::scanISO9660()
{
	//http://www.invisiblepixels.org/concepts/iso9660.html
	findOriginal_name();
	findCreation_time();
	findCreate_application();
	findSize();

	return state;
}

int Medium::fs_read_data ( char * fs, int seek, int len, char * data)
{
	int fd;
	int result = -1;

	if ( fs != NULL) {
		if ( ( fd = open( fs, O_RDONLY)) != -1) {
			if ( lseek (fd, seek, SEEK_SET) != -1) {
				if ( read ( fd, data, len) != -1) {
					data[len] = '\0';
					result = 0;
				}
			}
		}
		close ( fd);
	}
	return result;
}

char* Medium::findValue(int sector, int len)
{
	char * cstr;
	cstr = new char [device.toStdString().size()+1];
	strcpy (cstr, device.toStdString().c_str());
	
	int seek = sector;
	char * buff = NULL;
	char * value = NULL;
	buff = (char *)malloc( (sizeof (buff)) * (len+1));
	if ( (state = fs_read_data ( cstr, seek, len, buff)) != -1) {
		if ( (strncmp ( buff, "NO NAME", 7) == 0) || ( strncmp (buff, " ",1) == 0)) {
			free ( buff);
			buff=NULL;
			value = "None";
		}
		else {
			value = strdup ( buff);
		}
	}
	else value = "";
	//qDebug() << "Volume name: " << value;
	free (buff);
	buff=NULL;
	return value;
}

QString Medium::getName()
{
	return name;
}

QString Medium::getOriginal_name()
{
	return original_name;
}

QString Medium::getCreation_time()
{
	return creation_time;
}

QString Medium::getCreateApplication()
{
	return create_application;
}

QString Medium::getPath()
{
	return mount_point;
}

QString Medium::getDevice()
{
	return device;
}

QString Medium::getFilesystem()
{
	return filesystem;
}

QString Medium::getMountPointOfDevice(QString device)
{
	// is there another way?
	// second string on the line with the device in /etc/fstab is mount point
	QFile file("/etc/fstab");
	if (!file.open(QIODevice::ReadOnly)) {
		//QMessageBox::warning(this, tr("Error"), QString("Failed to open /etc/fstab file (necessary for finding out mount point). Reason: ").append(file.errorString()), QMessageBox::Ok, QMessageBox::Ok);
		qDebug() << "Failed to open /etc/fstab file (necessary for finding out mount point).";
		return "";
	}
        // does the device exist?
        if(!QFile::exists(device)) {
            qDebug() << "Device doesn't exist. Something is wrong.";
            return "";
        }
        // is symlink?
        QString realDeviceName;
        if(QFile::symLinkTarget(device).isEmpty()) {
            realDeviceName = device;
        }
        else {
            realDeviceName = QFile::symLinkTarget(device);
        }
	QByteArray ba;
	ba = file.readLine(4096);
	while(!ba.isEmpty()) {
                if(ba.contains(realDeviceName.toUtf8())) {
			QString line(ba);
			QStringList line_tokens = line.split(QRegExp("\\s+"), QString::SkipEmptyParts);
			return line_tokens[1];
		}
		ba = file.readLine(4096);
	}

        // still not successful? let's try /etc/mtab
        if(!this->isMounted()) {
            mount();
        }
        QFile mtab("/etc/mtab");
        if (!mtab.open(QIODevice::ReadOnly)) {
                qDebug() << "Failed to open /etc/mtab file (necessary for finding out mount point).";
                return tr("please change path");
        }
        ba = mtab.readLine(4096);
        while(!ba.isEmpty()) {
                if(ba.contains(realDeviceName.toUtf8())) {
                        QString line(ba);
                        QStringList line_tokens = line.split(QRegExp("\\s+"), QString::SkipEmptyParts);
                        return line_tokens[1];
                }
                ba = mtab.readLine(4096);
        }

        qDebug() << "Mount point not found in /etc/fstab, neither /etc/mtab after mounting.";
        return tr("please change the path");
}

double Medium::getSize()
{
	return size;
}

void Medium::findOriginal_name()
{
	original_name = findValue(32808, 32);
	emit stateChanged(state);
}

void Medium::findCreation_time()
{
	QString format = "yyyyMMddhhmmss";
	QString date = QString(findValue(33581, 4)).append(QString(findValue(33585, 2))).append(QString(findValue(33587, 2))).append(QString(findValue(33589, 2))).append(QString(findValue(33591, 2))).append(QString(findValue(33593, 2)));
	//qDebug() << "datum" << date;
	
	//creation_time = QDateTime::fromString(date, format);
	creation_time = date;
	emit stateChanged(state);
}

void Medium::findCreate_application()
{
	create_application = findValue(33342, 128);
	emit stateChanged(state);
}

void Medium::findSize()
{
/*	// plne CD ma tyto hodnoty bytu: 77 6b 5 0 (cd75), jine: 43 73 5 0
	// plne DVD: c c0 22 0
	printf("%x %x %x %x\n",findValue(32848, 4)[0], findValue(32848, 4)[1], findValue(32848, 4)[2], findValue(32848, 4)[3]);
	printf("%x %x %x %x\n",findValue(32852, 4)[0], findValue(32852, 4)[1], findValue(32852, 4)[2], findValue(32852, 4)[3]);
	//(2^30+2^25+2^24+2^22+2^21+2^20+2^17+2^16)
	qDebug() << findValue(32848, 4)[0] <<findValue(32848, 4)[1]<<findValue(32848, 4)[2]<<findValue(32848, 4)[3];
	qDebug() << findValue(32852, 4);
	qDebug() << findValue(32888, 2);
	qDebug() << findValue(32890, 2);
*/
	//http://linuxproblem.org/art_20.html
	int fd;
	unsigned long numblocks=0;
	fd = open(getDevice().toAscii().constData(), O_RDONLY);
	ioctl(fd, BLKGETSIZE, &numblocks);
	close(fd);
	//printf("Number of blocks: %lu, this makes %.3f GB, %f B\n",numblocks, (double)numblocks * 512.0 / (1024 * 1024 * 1024),(double)numblocks * 512);
	//qDebug() << (numblocks * 512);
	size = (double)numblocks * 512;
	emit stateChanged(state);
}
/*void Medium::scanMedium(ScanDialog *scan_dialog)
{
	qDebug() << "scanning medium :-0";
	
	// projdu rekurzivne vsechny soubory/adresare na zaklade mounted path
	// u kazdeho souboru	ulozim: jmeno, rodic, typ, in-root, medium-id
	//					vypisu: jmeno (celou cestu)
	QDirIterator iter(mounted_path, QDirIterator::Subdirectories);
	while (iter.hasNext()) {
		qDebug() << iter.next();
		//scan_dialog->list_widget->insertItem(row, newItem);
		new QListWidgetItem(iter.next(), scan_dialog->list_widget);
	}
}
*/

void Medium::setExploringTime(int time)
{
	exploring_time = time;
}

int Medium::getExploringTime()
{
	return exploring_time;
}

bool Medium::isMounted()
{
	return mounted;
}

void Medium::setId(int id)
{
	this->id = id;
}

int Medium::getId()
{
	return id;
}

void Medium::setName(QString name)
{
	this->name = name;
}

QString Medium::childrenToString()
{
	if(children.isEmpty())
		return "None";
	else {
		QString str;
		for(int i = 0; i<children.size(); i++) {
			//qDebug() << "child to string";
			str.append(children[i]->toString()).append("\n");
		}
		return str;
	}
}

bool Medium::mount()
{
	// mount media - pres QProcess ... mozna bude lepsi pres HAL
	// je treba jeste nahodit podminku
	QString program = "mount";
     QStringList arguments;
     arguments << getDevice();

     QProcess *mountProcess = new QProcess(this);
     mountProcess->start(program, arguments);
	mountProcess->waitForFinished();

	// setting mount_point
	//mount_point = "/media/cdrom0";
	
	return true;
}	
